﻿using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace TfsRollUp.Core
{
    /// <summary>
    /// Representation of a workitem hierarchy with units of time that can be calculated and unit tested
    /// </summary>
    public class WorkItemNode
    {
        /// <summary>
        /// Get the detailed information on what workitems where calculated and their totals
        /// </summary>
        public string CalculationResult(WorkItemLinkInfo[] tree, string teamSystemWebAccessLink)
        {
            return CreateDgml(tree, teamSystemWebAccessLink);
        }

        private string CreateDgml(WorkItemLinkInfo[] tree, string teamSystemWebAccessLink)
        {
            var sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?><DirectedGraph xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\"><Nodes>");
            foreach (var node in AllNodes.Values)
            {
                sb.AppendLine(string.Format("<Node Id=\"{0}\" TSWA=\"{0}\" Label=\"{0} ({1}:{2})\" />", node.Id, node.UnitOfTime, node.TotalUnitOfTimeChildren));
            }
            sb.AppendLine("</Nodes><Links>");
            foreach (var linkInfo in tree)
            {
                if (linkInfo.SourceId > 0 && linkInfo.TargetId > 0)
                {
                    sb.AppendLine(string.Format("<Link Source=\"{0}\" Target=\"{1}\" />", linkInfo.SourceId, linkInfo.TargetId));
                }
            }
            var properties = string.Format("<Properties><Property Id=\"TSWA\" IsReference=\"True\" ReferenceTemplate=\"{0}\" /></Properties>", teamSystemWebAccessLink);
            sb.AppendLine("</Links>" + properties + "</DirectedGraph>");
            return sb.ToString();
        }

        /// <summary>
        ///  List of all nodes in the tree
        /// </summary>
        public Dictionary<int, WorkItemNode> AllNodes { get; private set; }

        /// <summary>
        /// The root
        /// </summary>
        public WorkItemNode TopParent { get; private set; }

        /// <summary>
        /// Parent for this node
        /// </summary>
        public WorkItemNode Parent { get; private set; }

        /// <summary>
        /// All my children
        /// </summary>
        public List<WorkItemNode> Children { get; private set; }

        /// <summary>
        /// My unit of time to be rolled up
        /// </summary>
        public double UnitOfTime { get; private set; }

        /// <summary>
        /// Rolled up units of time for my children
        /// </summary>
        public double TotalUnitOfTimeChildren { get; private set; }

        /// <summary>
        /// My id
        /// </summary>
        public int Id { get; private set; }

        /// <summary>
        /// My level in the tree
        /// </summary>
        public int Level { get; private set; }

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="parent">My parent</param>
        /// <param name="id">My id</param>
        /// <param name="unitOfTime">My unit of time</param>
        public WorkItemNode(WorkItemNode parent, int id, double unitOfTime)
        {
            this.Parent = parent;
            this.Id = id;
            this.UnitOfTime = unitOfTime;
            this.Children = new List<WorkItemNode>();
            if (parent == null)
            {
                this.TopParent = this;
                this.Level = 0;
                this.AllNodes = new Dictionary<int, WorkItemNode>();
            }
            else
            {
                parent.Children.Add(this);
                this.Level = parent.Level + 1;
                this.TopParent = parent.TopParent;
            }
            this.TopParent.AllNodes.Add(id, this);
        }

        /// <summary>
        /// Calculate the roll up values
        /// </summary>
        /// <returns></returns>
        public double CalculateChildren()
        {
            foreach (var child in this.Children)
            {
                this.TotalUnitOfTimeChildren += child.UnitOfTime + child.CalculateChildren(); 
            }
            return this.TotalUnitOfTimeChildren;
        }
    }
}
